import { MODEL_NAME } from '../../constants/model-names';
import { ITEM_RARITY, ITEM_TYPE } from '../../data/item/type';
import { EVENTS, type IEventBus } from '../../events';
import type {
  BattleLevelModel,
  BattleModel,
  InventoryModel,
  SectModel,
  WalletModel,
} from '../../model';
import type { BattleEventLogItem } from '../../model/battle/type';
import {
  REWARD_SOURCE_TYPE,
  REWARD_TYPE,
  type Reward,
  type RewardSourceType,
} from '../../model/reward/type';
import { CURRENCY_TYPE } from '../../model/wallet';
import { BaseSystem } from '../base';
import { InventoryFactory } from '../inventory/factory';
import { ItemReader } from '../item/reader';
import type { PlayerStateSystem } from '../player-state';

export class RewardSystem extends BaseSystem {
  private bus: IEventBus;
  private playerStateSystem: PlayerStateSystem;

  constructor(bus: IEventBus, playerStateSystem: PlayerStateSystem) {
    super();
    this.bus = bus;
    this.playerStateSystem = playerStateSystem;

    this.bus.on(EVENTS.REWARD_ISSUE, (reward, sourceType) => {
      this.issueReward(reward, sourceType);
    });
  }

  private issueReward(reward: Reward[], sourceType: RewardSourceType) {
    const battleModel = this.playerStateSystem.getModel<BattleModel>(
      MODEL_NAME.BATTLE
    );
    if (!battleModel) return;
    reward.forEach((r) => {
      switch (r.type) {
        case REWARD_TYPE.EXP:
          this.issueExpReward(r, battleModel);
          break;
        case REWARD_TYPE.ITEM:
          this.issueItemReward(r, sourceType);
          break;
        case REWARD_TYPE.SPIRIT_STONE:
          this.issueSpiritStoneReward(r, sourceType, battleModel);
          break;
        case REWARD_TYPE.SECT_CONTRIBUTION:
          this.issueSectContributionReward(r);
          break;
        default:
          break;
      }
    });
    this.bus.emit(EVENTS.REWARD_ISSUE_COMPLETED, sourceType);
  }

  private issueExpReward(reward: Reward, battleModel: BattleModel) {
    if (reward.type !== REWARD_TYPE.EXP) return;
    const battleLevelModel = this.playerStateSystem.getModel<BattleLevelModel>(
      MODEL_NAME.BATTLE_LEVEL
    );
    if (!battleLevelModel) return;
    battleLevelModel.addExp(reward.amount);
    battleModel.addbattleLog(`获得 [战斗经验]：${reward.amount}`);
  }

  private issueItemReward(reward: Reward, sourceType: RewardSourceType) {
    const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
      MODEL_NAME.INVENTORY
    );
    const battleModel = this.playerStateSystem.getModel<BattleModel>(
      MODEL_NAME.BATTLE
    );
    const walletModel = this.playerStateSystem.getModel<WalletModel>(
      MODEL_NAME.WALLET
    );
    if (!inventoryModel || !battleModel || !walletModel) return;
    if (reward.type !== REWARD_TYPE.ITEM) return;
    const autoSellRarity = battleModel.getSettingsRarity();
    const itemConfig = ItemReader.getConfig(reward.itemId);
    if (!itemConfig) return;
    const logItems: BattleEventLogItem[] = [];
    const itemName = itemConfig.name;
    let itemRarity = itemConfig.rarity || ITEM_RARITY.COMMON;
    switch (itemConfig.type) {
      case ITEM_TYPE.CULTIVATION_SKILL:
      case ITEM_TYPE.MATERIAL:
        inventoryModel.addItem(itemConfig, reward.quantity);
        logItems.push({
          name: itemName,
          rarity: itemRarity,
          quantity: reward.quantity,
        });
        break;
      case ITEM_TYPE.EQUIPMENT:
        for (let i = 0; i < reward.quantity; i++) {
          const equipItem = InventoryFactory.createEquipItem(itemConfig);
          itemRarity = equipItem?.payload?.equip?.rarity || ITEM_RARITY.COMMON;
          if (
            autoSellRarity.includes(itemRarity) &&
            itemConfig.canSell !== false &&
            sourceType === REWARD_SOURCE_TYPE.BATTLE
          ) {
            walletModel.addCurrency(
              CURRENCY_TYPE.SPIRIT_STONE,
              itemConfig.basePrice
            );
            battleModel.addbattleLog(
              `自动出售物品：[${reward.name}] 获得 [灵石]：${itemConfig.basePrice}`
            );
          } else {
            inventoryModel.addEquip(equipItem);
            logItems.push({
              name: itemName,
              rarity: itemRarity,
              quantity: 1,
            });
          }
        }
        break;

      default:
        throw new Error(`未知的物品类型: ${reward.itemId}`);
    }
    if (sourceType === REWARD_SOURCE_TYPE.BATTLE) {
      battleModel.addbattleLog(`获得物品：[${reward.name}]`, {
        items: logItems,
      });
    }
  }

  private issueSpiritStoneReward(
    reward: Reward,
    sourceType: RewardSourceType,
    battleModel: BattleModel
  ) {
    if (reward.type !== REWARD_TYPE.SPIRIT_STONE) return;
    const walletModel = this.playerStateSystem.getModel<WalletModel>(
      MODEL_NAME.WALLET
    );
    if (!walletModel) return;
    walletModel.addCurrency(REWARD_TYPE.SPIRIT_STONE, reward.quantity);
    if (sourceType === REWARD_SOURCE_TYPE.BATTLE) {
      battleModel.addbattleLog(`获得 [灵石]：${reward.quantity}`);
    }
  }

  private issueSectContributionReward(reward: Reward) {
    if (reward.type !== REWARD_TYPE.SECT_CONTRIBUTION) return;
    const sectModel = this.playerStateSystem.getModel<SectModel>(
      MODEL_NAME.SECT
    );
    if (!sectModel) return;
    sectModel.addSectContribution(reward.quantity);
  }
}
